package util

import (
	"errors"
	"sync/atomic"
	"time"
)

func init() {
	// ID 生成器配置
	worker, err := NextWorker()
	if err != nil {
		panic(err)
	}
	IDWorker = worker

}

var (
	IDWorker *Worker
)

const (
	workerBits  uint8 = 10
	numberBits  uint8 = 12
	workerMax   int64 = -1 ^ (-1 << workerBits)
	numberMax   int64 = -1 ^ (-1 << numberBits)
	timeShift   uint8 = workerBits + numberBits
	workerShift uint8 = numberBits
	startTime   int64 = 1525705533000
)

type Worker struct {
	timestamp int64
	workerId  int64
	number    int64
}

// NewWorker 考虑分布式应用场景
func NewWorker(workerId int64) (*Worker, error) {
	if workerId < 0 || workerId > workerMax {
		return nil, errors.New("Worker ID excess of quantity")
	}
	// 生成一个新节点
	return &Worker{
		timestamp: 0,
		workerId:  workerId,
		number:    0,
	}, nil
}

// NextWorker 单体应用下
func NextWorker() (*Worker, error) {
	return NewWorker(1)
}

func (w *Worker) GetId() int64 {
	now := time.Now().UnixNano() / 1e6
	number := atomic.AddInt64(&w.number, 1)
	if number > numberMax {
		for now <= w.timestamp {
			now = time.Now().UnixNano() / 1e6
		}
	}
	w.number = number
	w.timestamp = now
	ID := int64((now-startTime)<<timeShift | (w.workerId << workerShift) | (number))
	return ID
}

/*func main() {
	node, err := NewWorker(1)
	if err != nil {
		panic(err)
	}

	for {
		fmt.Println(node.GetId())
	}
}*/
